import { HashMap } from "../../api/struct/HashMap";
import { TimerUtils } from "../../api/timer/TimerUtils";
import { E_TimeConfig } from "../defs/com/E_TimeConfig";
import { E_ItemID } from "../defs/item/E_ItemID";
import { E_MissionEventType } from "../defs/mission/E_MissionEventType";
import { E_MissionGroup } from "../defs/mission/E_MissionGroup";
import { E_MissionType } from "../defs/mission/E_MissionType";
import { E_TrainPos } from "../defs/train/E_TrainPos";
import { CDMission, E_CDMission } from "../excel/CDMission";
import { CDMissionMainLine } from "../excel/CDMissionMainLine";
import { CDPet } from "../excel/CDPet";
import { CEMission } from "../excel_extend/CEMission";
import { Player } from "../struct/Player";
import { SDActivity } from "./SDActivity";
import { SDPet } from "./SDPet";
import { SDPlayer } from "./SDPlayer";
import { SDServer } from "./SDServer";
import { SDStage } from "./SDStage";
import { SDTrainTower } from "./SDTrialTower";


/**系统重置时间 */
const SYSTEM_RESET_TIME = E_TimeConfig.Hour * 5;


/**
 * 数据-任务
 */
export abstract class SDMission {

    /**已开启活动列表-客户端用 */
    public static openActivityIdList: number[] = [];
    /**关闭活动列表-客户端用 */
    public static closeActivityIdList: number[] = [];

    /**统计时间-客户端用 */
    private static frameMissionMapSetTime = 0;
    /**任务开启-客户端用 */
    private static frameMissionOpenMap = new HashMap<number, boolean>();
    /**任务完成-客户端用 */
    private static frameMissionCompleteMap = new HashMap<number, boolean>();


    /**
     * 重置开启完成标记
     * @param time 
     */
    public static resetClientFrameMission(time: number): void {
        if (time === this.frameMissionMapSetTime) {
            return;
        }
        this.frameMissionMapSetTime = time;
        this.frameMissionOpenMap.clear();
        this.frameMissionCompleteMap.clear();
    }


    /**
    * 检测开启关闭活动id
    * @param player 
    * @param nowTime 
    */
    public static checkActivityOpenClose(
        player: Player,
        nowTime: number
    ): boolean {

        const ol: number[] = [];
        const cl: number[] = [];
        this.getActivityOpenCloseList(player, nowTime, ol, cl);

        let needUpdate = false;
        {
            if (ol.length !== this.openActivityIdList.length
                || cl.length !== this.closeActivityIdList.length) {
                needUpdate = true;
            }

            if (!needUpdate) {
                const t = this.openActivityIdList;
                for (let i = 0, len = t.length; i < len; i++) {
                    if (t[i] !== ol[i]) {
                        needUpdate = true;
                        break;
                    }
                }
            }

            if (!needUpdate) {
                const t = this.closeActivityIdList;
                for (let i = 0, len = t.length; i < len; i++) {
                    if (t[i] !== cl[i]) {
                        needUpdate = true;
                        break;
                    }
                }
            }
        }

        if (needUpdate) {
            this.openActivityIdList = ol;
            this.closeActivityIdList = cl;
        }

        return needUpdate;
    }



    /**
     * 开启关闭活动id
     * @param player 
     * @param nowTime 
     * @param openIdList 
     * @param closeIdList 
     */
    public static getActivityOpenCloseList(
        player: Player,
        nowTime: number,
        openIdList: number[],
        closeIdList: number[]
    ): void {

        const ks = CEMission.activityMission.getKeys();
        const vs = CEMission.activityMission.getValues();

        for (let i = 0, len = ks.length; i < len; i++) {
            if (this.isMissionComplete(player, ks[i], nowTime)) {
                if (openIdList && -1 === openIdList.indexOf(vs[i])) {
                    openIdList.push(vs[i]);
                }
            }
            else {
                if (closeIdList && -1 === closeIdList.indexOf(vs[i])) {
                    closeIdList.push(vs[i]);
                }
            }
        }
    }


    /**
     * 获取当前主线任务
     * @param player 
     */
    public static getMainLineMission(
        player: Player,
        nowTime: number
    ): CDMissionMainLine {
        const vs = CDMissionMainLine.datas.getValues();
        for (let i = 0, len = vs.length; i < len; i++) {
            const config = vs[i];
            if (!this.isRewardGetted(player, config.missionId)
                && this.isMissionOpen(player, config.missionId, nowTime)) {
                return config;
            }
        }
        return null;
    }


    /**
     * 任务是否开启 (很吃性能)
     * @param player 
     * @param config 
     * @param nowTime 
     * @returns 
     */
    public static isMissionOpen(
        player: Player,
        config: number | CDMission,
        nowTime: number
    ): boolean {

        if (!(config instanceof CDMission)) {
            config = CDMission.getData(config);
        }

        if (!config) {
            return false;
        }

        const frameSave = nowTime === this.frameMissionMapSetTime;

        if (frameSave) {
            const v = this.frameMissionOpenMap.get(config.id);
            if (v !== null) {
                return v;
            }
        }

        const opened = this._isMissionOpen(player, config, nowTime);

        if (frameSave) {
            this.frameMissionOpenMap.put(config.id, opened);
        }

        return opened;
    }


    /**
     * 任务是否开启 (很吃性能)
     * @param player 
     * @param config 
     * @param nowTime 
     * @returns 
     */
    private static _isMissionOpen(
        player: Player,
        config: CDMission,
        nowTime: number
    ): boolean {

        //等级限制
        if (config.reqLevel > player.playerInfo.level
            || config.reqVip > player.vip.level) {
            return false;
        }

        //活动
        if (config.activityID !== 0
            && !SDActivity.isOpen(player, config.activityID)) {
            return false;
        }

        //天数限制
        if (0 !== config.limitDay) {
            const create = TimerUtils.getDayZeroTime(SDServer.getServerCreateTime(player));
            const cur = TimerUtils.getDayZeroTime(nowTime);
            const pass = Math.floor((cur - create) / E_TimeConfig.Day) + 1;
            if (pass > config.limitDay) {
                return false;
            }
        }

        //前置任务
        if (0 !== config.preTask && config.id !== config.preTask) {
            if (!this.isMissionComplete(player, config.preTask, nowTime)) {
                return false;
            }
        }

        return true;
    }


    /**
    * 奖励已领取
    * @param player 
    * @param missionId 
    * @returns 
    */
    public static isRewardGetted(player: Player, missionId: number): boolean {
        const status = player.mission.getStatus(missionId);
        if (status && status.isGetReward) {
            return true;
        }
        return false;
    }


    /**
     * 任务是否完成
     * @param player 
     * @param config 
     * @param nowTime 
     * @param needCheckOpen
     * @returns 
     */
    public static isMissionComplete(
        player: Player,
        config: number | CDMission,
        nowTime: number,
        needCheckOpen = true
    ): boolean {

        if (!(config instanceof CDMission)) {
            config = CDMission.getData(config);
        }

        if (!config) {
            return false;
        }

        const frameSave = nowTime === this.frameMissionMapSetTime;
        if (frameSave) {
            const v = this.frameMissionCompleteMap.get(config.id);
            if (v !== null) {
                return v;
            }
        }

        const complete = this._isMissionComplete(player, config, nowTime, needCheckOpen);

        if (frameSave) {
            this.frameMissionCompleteMap.put(config.id, complete);
        }

        return complete;
    }


    /**
    * 任务是否完成
    * @param player 
    * @param config 
    * @param nowTime 
    * @param needCheckOpen
    * @returns 
    */
    private static _isMissionComplete(
        player: Player,
        config: CDMission,
        nowTime: number,
        needCheckOpen = true
    ): boolean {

        if (nowTime === this.frameMissionMapSetTime) {
            const v = this.frameMissionCompleteMap.get(config.id);
            if (v !== null) {
                return v;
            }
        }

        //达不到开启条件
        if (needCheckOpen && !this.isMissionOpen(player, config, nowTime)) {
            return false;
        }

        //每日积分特殊判定
        if (config.missionType === E_MissionType.Daily && config.group === E_MissionGroup.DailyActivity) {
            const have = player.getItemNum(E_ItemID.DailyActivity);
            const enough = config.taskValue_1_2 <= have;
            return enough;
        }

        //两个子任务未完成
        for (let i = 0; i < 2; i++) {
            if (!this.isSubTaskComplete(player, config, i, nowTime)) {
                return false;
            }
        }

        return true;
    }


    /**
     * 获取日常活跃任务
     * @param player 
     * @param nowTime
     * @param out 
     */
    public static getDailyActivityMissionList(
        player: Player,
        nowTime: number,
        out: CDMission[] = []
    ): CDMission[] {

        const missionType = E_MissionType.Daily;
        const map = CEMission.groupMission.get(missionType);

        if (map) {
            const missionGroup = E_MissionGroup.DailyActivity;
            const missionList = map.get(missionGroup);

            if (missionList) {
                for (let i = 0, len = missionList.length; i < len; i++) {
                    if (this.isMissionOpen(player, missionList[i], nowTime)) {
                        out.push(missionList[i]);
                    }
                }
            }
        }

        return out;
    }


    /**
     * 获取指定类型的统计数量
     * @param player 
     * @param missionType 
     * @param eventType 
     */
    public static getSaveEventCount(
        player: Player,
        missionType: E_MissionType,
        eventType: E_MissionEventType,
        nowTime: number
    ): number {

        const d1 = player.mission.getSaveTask(missionType);
        if (d1) {
            let d2 = d1.getCount(eventType);

            switch (eventType) {
                case E_MissionEventType.ONLINE:
                    //需要加上当前时间差，且单位变为秒
                    {
                        if (missionType === E_MissionType.Daily) {
                            const nowZero = TimerUtils.getDayZeroTime(nowTime);
                            const loginZero = TimerUtils.getDayZeroTime(player.playerInfo.loginTime);
                            if (loginZero === nowZero) {
                                const pass = nowTime - player.playerInfo.loginTime;
                                const sec = Math.floor(pass / E_TimeConfig.Second);
                                d2 += sec;
                            }
                            else {
                                const pass = nowTime - nowZero;
                                const sec = Math.floor(pass / E_TimeConfig.Second);
                                d2 = sec;
                            }
                        }
                        else {
                            const pass = nowTime - player.playerInfo.loginTime;
                            const sec = Math.floor(pass / E_TimeConfig.Second);
                            d2 += sec;
                        }
                    }
                    break;

                //-------------------------

                default:
                    break;
            }

            return d2;
        }
        return 0;
    }


    /**
     * 获取任务进度
     * @param player 
     * @param config 
     * @param nowTime 
     * @param outList 
     * @returns 
     */
    public static getMissionProgress(
        player: Player,
        config: CDMission,
        nowTime: number,
        outList: number[] = []
    ): number[] {

        const subPro: number[] = [];
        this.getTaskProgress(player, config, 0, nowTime, subPro);    //先取第一个

        outList[0] = subPro[0];
        outList[1] = subPro[1];

        return outList;
    }


    /**
     * 获取子任务进度
     * @param player 
     * @param config 
     * @param taskIndex 
     * @param nowTime 
     * @param outList 
     * @returns 
     */
    public static getTaskProgress(
        player: Player,
        config: CDMission,
        taskIndex: number,
        nowTime: number,
        outList: number[] = []
    ): number[] {

        outList[0] = 0;
        outList[1] = 0;

        const idxOffset = 4;
        const start = E_CDMission.taskType_1 + taskIndex * idxOffset;
        const eventType: E_MissionEventType = config.getAttr(start);
        if (eventType === E_MissionEventType.None) {
            return outList;
        }

        const p1: number = config.getAttr(start + 1);
        const p2: number = config.getAttr(start + 2);
        const p3: number = config.getAttr(start + 3);

        if (eventType <= E_MissionEventType.SAVE_MAX) {
            //统计类
            outList[0] = this.getSaveEventCount(player, config.missionType, eventType, nowTime);
            outList[1] = p1;
        }
        else {
            //状态类
            switch (eventType) {
                default:
                    break;

                case E_MissionEventType.ECONOMIC:
                    {
                        if (1 === p1) {
                            outList[0] = player.playerInfo.level;
                        }
                        else if (2 === p1) {
                            outList[0] = player.vip.level;
                        }
                        outList[1] = p2;
                    }
                    break;

                case E_MissionEventType.TOP:
                    if (1 === p1) {
                        outList[0] = SDPlayer.getFightScore(player);
                        outList[1] = p2;
                    }
                    break;

                case E_MissionEventType.ITEMNUM:
                    {
                        outList[0] = player.getItemNum(p1);
                        outList[1] = p2;
                    }
                    break;

                case E_MissionEventType.TRAIN_LEVEL:
                    {
                        if (99 === p1) {
                            let minLv = 0;
                            for (let i = 0, len = E_TrainPos.EnumCount; i < len; i++) {
                                const lv = player.train.getLevel(i);
                                if (i === 0 || (lv < p2 && minLv > lv)) {
                                    minLv = lv;
                                }
                            }
                            outList[0] = minLv;
                        }
                        else {
                            outList[0] = player.train.getLevel(p1 - 1);       //策划配置从1开始，所以要-1
                        }
                        outList[1] = p2;
                    }
                    break;

                case E_MissionEventType.COMM_INS:
                    {
                        const idx = SDStage.getMainStageIndex(player);
                        outList[0] = idx;
                        outList[1] = p1;
                    }
                    break;

                case E_MissionEventType.COMM_TOWER:
                    {
                        outList[0] = SDTrainTower.getStageIndex(player.trialTower.stageId);
                        outList[1] = p1;
                    }
                    break;

                case E_MissionEventType.WBOSS_HURT:
                    {
                        if (0 === p1) {
                            outList[0] = player.worldBoss.maxScore;
                        }
                        else if (1 === p1) {
                            outList[0] = player.worldBoss.historyScore;
                        }
                        outList[1] = p2;
                    }
                    break;
                case E_MissionEventType.LBOSS_HURT:
                    {
                        if (0 === p1) {
                            outList[0] = player.legionBoss.maxScore;
                        }
                        else if (1 === p1) {
                            outList[0] = player.legionBoss.historyScore;
                        }
                        outList[1] = p2;
                    }
                    break;
                case E_MissionEventType.PET:
                    {
                        const pet = SDPet.getPetByConfigId(player, p1);
                        if (pet) {
                            if ((p2 === 0 || pet.evolutionLevel >= p2)
                                && (p3 === 0 || pet.wakeLevel >= p3)) {
                                outList[0] = 1;
                            }
                        }
                        outList[1] = 1;
                    }
                    break;

                case E_MissionEventType.PET_COUNT:
                    {
                        let count = 0;
                        const vs = player.petManager.getPetValues();
                        for (let i = vs.length - 1; i >= 0; i--) {
                            const pet = vs[i];
                            if (p2 === 0 || pet.evolutionLevel >= p2) {
                                if (p3 === 0) {
                                    count++;
                                    continue;
                                }

                                const config = CDPet.getData(pet.configId);
                                if (config && config.rare >= p3) {
                                    count++;
                                }
                            }
                        }
                        outList[0] = count;
                        outList[1] = p1;
                    }
                    break;

                case E_MissionEventType.PET_COUNT_RANK:
                    {
                        let count = 0;
                        const vs = player.petManager.getPetValues();
                        for (let i = vs.length - 1; i >= 0; i--) {
                            const pet = vs[i];
                            if ((p2 === 0 || pet.evolutionLevel >= p2)
                                && (p3 === 0 || pet.wakeLevel >= p3)) {
                                count++;
                            }
                        }
                        outList[0] = count;
                        outList[1] = p1;
                    }
                    break;

                case E_MissionEventType.PET_COUNT_COUNTRY:
                    {
                        let count = 0;
                        const vs = player.petManager.getPetValues();
                        for (let i = vs.length - 1; i >= 0; i--) {
                            const pet = vs[i];
                            if (p2 === 0 || pet.evolutionLevel >= p2) {
                                if (p3 === 0) {
                                    count++;
                                    continue;
                                }
                                const config = CDPet.getData(pet.configId);
                                if (config && config.petType === p3) {
                                    count++;
                                }
                            }
                        }
                        outList[0] = count;
                        outList[1] = p1;
                    }
                    break;

                case E_MissionEventType.PET_COUNT_LEVEL:
                    {
                        let count = 0;
                        const vs = player.petManager.getPetValues();
                        for (let i = vs.length - 1; i >= 0; i--) {
                            const pet = vs[i];
                            if ((p2 === 0 || pet.evolutionLevel >= p2)
                                && (p3 === 0 || pet.petLevel >= p3)) {
                                count++;
                            }
                        }
                        outList[0] = count;
                        outList[1] = p1;
                    }
                    break;

                case E_MissionEventType.PET_EX:
                    {
                        let count = 0;
                        let maxCount = 0;

                        if (0 !== p1) {
                            maxCount++;
                            if (SDPet.getPetByConfigId(player, p1) !== null) {
                                count++;
                            }
                        }
                        if (0 !== p2) {
                            maxCount++;
                            if (SDPet.getPetByConfigId(player, p2) !== null) {
                                count++;
                            }
                        }
                        if (0 !== p3) {
                            maxCount++;
                            if (SDPet.getPetByConfigId(player, p3) !== null) {
                                count++;
                            }
                        }
                        outList[0] = count;
                        outList[1] = maxCount;
                    }
                    break;

                case E_MissionEventType.WEAR_EQUIP_COUNT:
                    {
                        outList[0] = player.equipManager.getWearKeys().length;
                        outList[1] = p1;
                    }
                    break;


            }
        }

        return outList;
    }


    /**
     * 子任务是否完成
     * @param player 
     * @param config 
     * @param taskIndex 
     * @param nowTime
     */
    public static isSubTaskComplete(
        player: Player,
        config: CDMission,
        taskIndex: number,
        nowTime: number
    ): boolean {

        const idxOffset = 4;
        const start = E_CDMission.taskType_1 + taskIndex * idxOffset;       //TO_WARN 这边需要保证顺序
        const eventType: E_MissionEventType = config.getAttr(start);
        if (eventType === E_MissionEventType.None) {
            return true;
        }

        const outs: number[] = [];
        this.getTaskProgress(player, config, taskIndex, nowTime, outs);

        const complete = outs[0] >= outs[1];
        return complete;
    }


    /**
     * 数据需要清零
     * @param player 
     * @param firstTime 
     * @param nowTime 
     * @param missionType 
     * @returns 
     */
    public static isNeedClear(player: Player, firstTime: number, nowTime: number, missionType: E_MissionType): boolean {
        switch (missionType) {
            case E_MissionType.Achievement:
                //永久
                break;

            case E_MissionType.Daily:
                if (TimerUtils.isDailyTrigger(SYSTEM_RESET_TIME, firstTime, nowTime)) {
                    return true;
                }
                break;

            case E_MissionType.Weekly:
                if (TimerUtils.isWeeklyTrigger(SYSTEM_RESET_TIME, firstTime, SDServer.getServerCreateTime(player), nowTime)) {
                    return true;
                }
                break;

            case E_MissionType.Monthly:
                if (TimerUtils.isMonthlyTrigger(SYSTEM_RESET_TIME, firstTime, SDServer.getServerCreateTime(player), nowTime)) {
                    return true;
                }
                break;

            case E_MissionType.Activity:
                {
                    //TODO 需要做判定
                    return false;
                }
                break;

            case E_MissionType.RandomEvent:
                return false;

            default:
                console.warn('没有处理任务类型：' + missionType);
                break;
        }

        return false;
    }



}
